package com.jzo2o.foundations.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.enums.FoundationStatusEnum;
import com.jzo2o.foundations.mapper.ServeMapper;
import com.jzo2o.foundations.model.domain.Region;
import com.jzo2o.foundations.model.domain.Serve;
import com.jzo2o.foundations.model.domain.ServeSync;
import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
import com.jzo2o.foundations.service.HomeService;
import com.jzo2o.foundations.service.IRegionService;
import com.jzo2o.foundations.service.IServeService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class HomeServiceImpl implements HomeService {

    @Resource
    private IRegionService regionService;

    @Resource
    private ServeMapper serveMapper;

    @Resource
    private IServeService serveService;

    @Resource
    private ElasticsearchClient elasticsearchClient;

    /**
     * 根据区域id获取服务图标信息
     *
     * @param regionId 区域id
     * @return 服务图标列表
     */
    @Override
    @Caching(
            cacheable = {
                    @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId",
                            // result 为空则属于缓存穿透，缓存时间为30分钟
                            unless = "#result.size() != 0", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
                    @Cacheable(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId",
                            unless = "#result.size() == 0", cacheManager = RedisConstants.CacheManager.FOREVER)
            },
            evict = {
                    @CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#regionId", beforeInvocation = true)
            }
    )
    public List<ServeCategoryResDTO> queryServeIconCategoryByRegionIdCache(Long regionId) {
        if (ObjectUtil.isNull(regionId)) {
            return List.of();
        }

        Region region = regionService.getById(regionId);
        if (ObjectUtil.isNull(region) || region.getActiveStatus() != FoundationStatusEnum.ENABLE.getStatus()) {
            return List.of();
        }

        // 根据区域id查询所有服务列表
        List<ServeCategoryResDTO> serveCategoryResDTOList = serveMapper.findServeIconCategoryByRegionId(regionId);
        if (CollUtil.isEmpty(serveCategoryResDTOList)) {
            return List.of();
        }
        // 服务类型取前两个，服务项取前四个
        serveCategoryResDTOList = serveCategoryResDTOList.size() > 2 ? new ArrayList<>(serveCategoryResDTOList.subList(0, 2)) : serveCategoryResDTOList;
        serveCategoryResDTOList.forEach(serveCategoryResDTO -> {
            List<ServeSimpleResDTO> serveResDTOList = serveCategoryResDTO.getServeResDTOList();
            int endIndex = Math.min(serveResDTOList.size(), 4);
            serveResDTOList = new ArrayList<>(serveResDTOList.subList(0, endIndex));
            serveCategoryResDTO.setServeResDTOList(serveResDTOList);
        });
        return serveCategoryResDTOList;
    }

    /**
     * 根据区域id获取服务类型列表
     */
    @Caching(
            cacheable = {
                    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId",
                            unless = "#result.size() != 0", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
                    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId",
                            unless = "#result.size() == 0", cacheManager = RedisConstants.CacheManager.ONE_DAY)
            },
            evict = {
                    @CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId", beforeInvocation = true)
            }
    )
    @Override
    public List<ServeAggregationTypeSimpleResDTO> queryServeTypeListCache(Long regionId) {
        // 查询当前区域是否启用
        Region region = regionService.getById(regionId);
        if (ObjectUtil.isNull(region) || region.getActiveStatus() != FoundationStatusEnum.ENABLE.getStatus()) {
            return List.of();
        }

        // 根据区域id查询服务类型列表
        List<ServeAggregationTypeSimpleResDTO> list = serveMapper.selectServeTypesByRegion(regionId);
        if (CollUtil.isEmpty(list)) {
            return List.of();
        }
        return list;
    }

    /**
     * 获取热门服务列表
     */
    @Caching(
            cacheable = {
                    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId",
                            // result 为空则属于缓存穿透，缓存时间为30分钟
                            unless = "#result.size() != 0", cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
                    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId",
                            unless = "#result.size() == 0", cacheManager = RedisConstants.CacheManager.FOREVER)
            },
            evict = {
                    @CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId", beforeInvocation = true)
            }
    )
    @Override
    public List<ServeAggregationSimpleResDTO> queryHotServeListCache(Long regionId) {
        // 判断区域id是否为空
        if (ObjectUtil.isNull(regionId)) {
            return List.of();
        }
        // 根据区域ID获取区域信息，并校验区域是否存在且处于启用状态
        Region region = regionService.getById(regionId);
        if (ObjectUtil.isNull(region) || region.getActiveStatus() != FoundationStatusEnum.ENABLE.getStatus()) {
            return List.of();
        }
        return serveMapper.queryHotServeList(regionId);

    }

    /**
     * 根据服务id查询服务信息
     */
    @Override
    @Cacheable(value = RedisConstants.CacheName.SERVE_ITEM, key = "#id", cacheManager = RedisConstants.CacheManager.ONE_DAY)
    public Serve queryServeByIdCache(Long id) {
        return serveService.getById(id);
    }

    /**
     * 小程序端首页搜索
     *
     * @param cityCode
     * @param serveTypeId
     * @param keyword
     */
    @Override
    public List<ServeSimpleResDTO> search(String cityCode, Long serveTypeId, String keyword) throws IOException {
        // 检验参数
        if (ObjectUtil.isEmpty(cityCode)) {
            return List.of();
        }

        // 使用 ES 搜索首页服务
        SearchResponse<ServeSync> response = elasticsearchClient.search(s -> s
                        .index("serve_aggregation")
                        .query(q -> q
                                .bool(
                                        b -> {
                                            // 必须条件，城市编码
                                            b.must(f -> f.term(t -> t.field("city_code").value(cityCode)));

                                            // 可选条件，服务类型 id
                                            if (ObjectUtil.isNotEmpty(serveTypeId)) {
                                                b.filter(f -> f.term(t -> t.field("serve_type_id").value(serveTypeId)));
                                            }

                                            // 可选条件：关键字搜索 - 使用must确保必须匹配
                                            if (ObjectUtil.isNotEmpty(keyword)) {
                                                // 过滤掉不符合条件的服务项
                                                b.filter(f -> f
                                                        .bool(bb -> {
                                                            bb.should(sh -> sh.match(mm -> mm.field("serve_item_name").query(keyword)));
                                                            bb.should(sh -> sh.match(mm -> mm.field("serve_type_name").query(keyword)));
                                                            bb.minimumShouldMatch("1"); // 至少匹配一个字段
                                                            return bb;
                                                        })
                                                );
                                            }
                                            return b;
                                        }
                                )
                        )
                        .sort(so -> so.field(f -> f.field("is_hot").order(SortOrder.Desc)))
                , ServeSync.class);

        // 处理响应结果
        List<ServeSync> docList = response.hits().hits().stream().map(Hit::source).collect(Collectors.toList());

        return docList.stream().map(doc -> {
            ServeSimpleResDTO serveSimpleResDTO = new ServeSimpleResDTO();
            serveSimpleResDTO.setId(doc.getId());
            serveSimpleResDTO.setServeItemId(doc.getServeItemId());
            serveSimpleResDTO.setServeItemName(doc.getServeItemName());
            serveSimpleResDTO.setServeItemIcon(doc.getServeItemIcon());
            serveSimpleResDTO.setServeItemSortNum(doc.getServeItemSortNum());
            return serveSimpleResDTO;
        }).collect(Collectors.toList());
    }


}
